package hupu.hnlp.hot_buffer.front.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.core.JsonProcessingException;

import hupu.hnlp.hot_buffer.share.rmi.distbuffer.DistBuffer;

import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.SortedMap;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping(value = { "/buffer" })
public class FrontController extends BaseController
{
    private final static Logger logger = LoggerFactory
            .getLogger(FrontController.class);

    @Resource(name = "distBuffer0Proxy")
    private DistBuffer dist_buffer_0;

    @Resource(name = "distBuffer1Proxy")
    private DistBuffer dist_buffer_1;

    @Resource(name = "distBuffer2Proxy")
    private DistBuffer dist_buffer_2;

    @Resource(name = "distBuffer3Proxy")
    private DistBuffer dist_buffer_3;

    @Resource(name = "distBuffer4Proxy")
    private DistBuffer dist_buffer_4;

    @Resource(name = "distBuffer5Proxy")
    private DistBuffer dist_buffer_5;

    @Resource(name = "distBuffer6Proxy")
    private DistBuffer dist_buffer_6;

    @Resource(name = "distBuffer7Proxy")
    private DistBuffer dist_buffer_7;

    @Resource(name = "distBuffer8Proxy")
    private DistBuffer dist_buffer_8;

    @Resource(name = "distBuffer9Proxy")
    private DistBuffer dist_buffer_9;

    private DistBuffer get_dist_buffer(int cid) throws Exception
    {
        switch (cid % appconfig.rmi.distbuffer.size())
        {
        case 0:
            return dist_buffer_0;
        case 1:
            return dist_buffer_1;
        case 2:
            return dist_buffer_2;
        case 3:
            return dist_buffer_3;
        case 4:
            return dist_buffer_4;
        case 5:
            return dist_buffer_5;
        case 6:
            return dist_buffer_6;
        case 7:
            return dist_buffer_7;
        case 8:
            return dist_buffer_8;
        case 9:
            return dist_buffer_9;
        default:
            throw new Exception(
                    String.format("appconfig.rmi.nodes(%s) out of index",
                            appconfig.rmi.distbuffer.stream()
                                    .collect(Collectors.joining(","))));
        }
    }

    private final String error_response = "{\"errno\":9999, \"errmsg\":\"未知错误\"}";

    @RequestMapping(value = {
            "/hotlist", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String hotList(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            int is_first = Optional.ofNullable(get_request.get("is_first"))
                    .map(Integer::parseInt).orElse(0);
            if (is_first != 0 && is_first != 1)
            {
                throw new Exception(
                        String.format("is_first(%d) invalid", is_first));
            }
            String fids_s = Optional.ofNullable(get_request.get("fids"))
                    .map(String::trim).orElse("0");
            List<Integer> fids = Arrays.stream(fids_s.split(","))
                    .map(String::trim).filter(s -> !s.isEmpty())
                    .map(Integer::valueOf).distinct()
                    .collect(Collectors.toList());
            if (fids.stream().anyMatch(fid -> fid < 0))
            {
                throw new Exception(String.format("fids(%s) invalid", fids_s));
            }
            if (fids.size() > 1 && fids.contains(0))
            {
                throw new Exception(
                        String.format("fids(%s) contains 0", fids_s));
            }
            String device = Optional.ofNullable(get_request.get("device"))
                    .map(String::trim).orElse("");
            String agent = Optional.ofNullable(get_request.get("agent"))
                    .map(String::trim).orElse("");

            long begin_time = Instant.now().toEpochMilli();
            String response = get_dist_buffer(cid).hotList(cid, is_first, fids,
                    device, agent);
            int cost = (int) (Instant.now().toEpochMilli() - begin_time);
            if (cost > 100)
            {
                logger.info("hotlist cost {} ms", cost);
            }
            return response;
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/dislike", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String dislike(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            String xid = Optional.ofNullable(get_request.get("xid"))
                    .map(String::trim).orElse("");
            if (xid.isEmpty())
            {
                throw new Exception(String.format("xid(%s) invalid", xid));
            }

            return get_dist_buffer(cid).dislike(cid, xid);
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/videolist", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String videoList(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            int is_first = Optional.ofNullable(get_request.get("is_first"))
                    .map(Integer::parseInt).orElse(0);
            if (is_first != 0 && is_first != 1)
            {
                throw new Exception(
                        String.format("is_first(%d) invalid", is_first));
            }

            long begin_time = Instant.now().toEpochMilli();
            String response = get_dist_buffer(cid).videoList(cid, is_first);
            int cost = (int) (Instant.now().toEpochMilli() - begin_time);
            if (cost > 100)
            {
                logger.info("videolist cost {} ms", cost);
            }
            return response;
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/relatedvideolist", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String relatedVideoList(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            String xid = Optional.ofNullable(get_request.get("xid"))
                    .map(String::trim).orElse("");
            if (xid.isEmpty())
            {
                throw new Exception(String.format("xid(%s) invalid", xid));
            }

            long begin_time = Instant.now().toEpochMilli();
            String response = get_dist_buffer(cid).relatedVideoList(cid, xid);
            int cost = (int) (Instant.now().toEpochMilli() - begin_time);
            if (cost > 100)
            {
                logger.info("relatedvideolist cost {} ms", cost);
            }
            return response;
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/hotlistbytopic", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String hotListByTopic(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            int is_first = Optional.ofNullable(get_request.get("is_first"))
                    .map(Integer::parseInt).orElse(0);
            if (is_first != 0 && is_first != 1)
            {
                throw new Exception(
                        String.format("is_first(%d) invalid", is_first));
            }
            String topics_s = Optional.ofNullable(get_request.get("topics"))
                    .map(String::trim).orElse("0");
            List<Integer> topics = Arrays.stream(topics_s.split(","))
                    .map(String::trim).filter(s -> !s.isEmpty())
                    .map(Integer::valueOf).distinct()
                    .collect(Collectors.toList());
            if (topics.stream().anyMatch(topic -> topic < 0))
            {
                throw new Exception(
                        String.format("topics(%s) invalid", topics_s));
            }
            if (topics.size() > 1 && topics.contains(0))
            {
                throw new Exception(
                        String.format("topics(%s) contains 0", topics_s));
            }
            String device = Optional.ofNullable(get_request.get("device"))
                    .map(String::trim).orElse("");
            String agent = Optional.ofNullable(get_request.get("agent"))
                    .map(String::trim).orElse("");

            long begin_time = Instant.now().toEpochMilli();
            String response = get_dist_buffer(cid).hotListByTopic(cid, is_first,
                    topics, device, agent);
            int cost = (int) (Instant.now().toEpochMilli() - begin_time);
            if (cost > 100)
            {
                logger.info("hotlistbytopic cost {} ms", cost);
            }
            return response;
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/unread", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String unread(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            String xids_s = Optional.ofNullable(get_request.get("xids"))
                    .map(String::trim).orElse("");
            List<String> xids = Arrays.stream(xids_s.split(","))
                    .map(String::trim).filter(s -> !s.isEmpty()).distinct()
                    .collect(Collectors.toList());
            if (xids.isEmpty())
            {
                throw new Exception(String.format("xids(%s) invalid", xids_s));
            }
            return get_dist_buffer(cid).unread(cid, xids);
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/clearread", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String clearRead(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            return get_dist_buffer(cid).clearRead(cid);
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/getread", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String getRead(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }

            return get_dist_buffer(cid).getRead(cid);
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/getdislike", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String getDislike(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }

            return get_dist_buffer(cid).getDislike(cid);
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    @RequestMapping(value = {
            "/getlist", }, method = RequestMethod.GET, produces = {
                    "application/json;charset=UTF-8" })
    public String getList(HttpServletRequest servlet_request)
    {
        try
        {
            SortedMap<String, String> get_request = get_request_params(
                    servlet_request);
            int cid = Optional.ofNullable(get_request.get("cid"))
                    .map(Integer::valueOf).orElse(-1);
            if (cid <= 0)
            {
                throw new Exception(String.format("cid(%d) invalid", cid));
            }
            return get_dist_buffer(cid).getList(cid);
        }
        catch (Exception e)
        {
            logger.error("fail: {}", e.getMessage());
            try
            {
                return objectMapper.writeValueAsString(
                        new BaseResponse(9999, e.getMessage()));
            }
            catch (JsonProcessingException e1)
            {
                return error_response;
            }
        }
    }

    // @RequestMapping(value = {
    // "/getstat", }, method = RequestMethod.GET, produces = {
    // "application/json;charset=UTF-8" })
    // public String getStat(HttpServletRequest servlet_request)
    // {
    // try
    // {
    // String response0 = dist_buffer_0.getStat();
    // String response1 = dist_buffer_1.getStat();
    // GetStatResponse response = new GetStatResponse(0, "成功");
    // response.setDist_buffer_0(response0);
    // response.setDist_buffer_1(response1);
    // return objectMapper.writeValueAsString(response);
    // }
    // catch (Exception e)
    // {
    // logger.error("fail: {}", e.getMessage());
    // try
    // {
    // return objectMapper.writeValueAsString(
    // new BaseResponse(9999, e.getMessage()));
    // }
    // catch (JsonProcessingException e1)
    // {
    // return error_response;
    // }
    // }
    // }
}

class GetStatResponse extends BaseResponse
{
    public GetStatResponse(int errno, String errmsg)
    {
        super(errno, errmsg);
    }

    @JsonRawValue
    private String dist_buffer_0;
    @JsonRawValue
    private String dist_buffer_1;

    public String getDist_buffer_0()
    {
        return dist_buffer_0;
    }

    public void setDist_buffer_0(String dist_buffer_0)
    {
        this.dist_buffer_0 = dist_buffer_0;
    }

    public String getDist_buffer_1()
    {
        return dist_buffer_1;
    }

    public void setDist_buffer_1(String dist_buffer_1)
    {
        this.dist_buffer_1 = dist_buffer_1;
    }

}
